/**
 * 
 */
package com.beta.common.web;

import com.beta.common.exception.BaseServiceException;
import com.beta.common.exception.ControllerException;
import com.beta.common.model.ErrorResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.mybatis.spring.MyBatisSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.support.RequestContext;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author vector
 *
 */
@RestControllerAdvice(annotations = RestController.class)
public class RestControllerExceptionHandler {

	protected final Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	protected HttpServletRequest request;

	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(BindException.class)
	public ErrorResponse handleBindException(BindException exception) {
		printException(exception);
		logger.error("参数绑定异常：{}", exception);
		return new ErrorResponse(String.valueOf(HttpStatus.BAD_REQUEST), buildBindExceptionMessage(exception));
	}

	/**
	 * 处理{@link Valid}标识的参数检验失败的异常
	 * 
	 * @param exception
	 * @return
	 * @see MethodArgumentNotValidException
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	public ErrorResponse handlerMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
		printException(exception);
		logger.error("参数绑定异常：{}", exception);
		return new ErrorResponse("400", buildBindExceptionMessage(exception.getBindingResult()));
	}
	
	/**
	 * 处理Api异常类型
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
	@ExceptionHandler(value = ControllerException.class)
	public ErrorResponse handleApiException(ControllerException exception) {
		printException(exception);
		String message = getMessage(exception.getCode());
		logger.error("业务错误：code={}, message={}", exception.getCode(), message);
		return new ErrorResponse(exception.getCode(), message);
	}

	/**
	 * 处理未认证异常
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	@ExceptionHandler(value = UnauthenticatedException.class)
	public ErrorResponse handleUnauthorizedException(UnauthenticatedException exception) {
		printException(exception);
		String message = getMessage("401");
		logger.error("未认证的访问：code={}, message={}", "401", message);
		return new ErrorResponse("401", message);
	}

	/**
	 * 处理未授权异常
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.FORBIDDEN)
	@ExceptionHandler(value = UnauthorizedException.class)
	public ErrorResponse handleUnauthorizedException(UnauthorizedException exception) {
		printException(exception);
		String message = getMessage("403");
		logger.error("未授权的访问：code={}, message={}", "403", message);
		return new ErrorResponse("403", message);
	}

	/**
	 * 处理Mybatis异常
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
	@ExceptionHandler(value = MyBatisSystemException.class)
	public ErrorResponse handleMybatisException(MyBatisSystemException exception) {
		printException(exception);
		logger.error("数据库错误：{}", exception);
		return new ErrorResponse("500", getMessage("500"));
	}

	/**
	 * 处理服务异常
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
	@ExceptionHandler(value = BaseServiceException.class)
	public ErrorResponse handleServiceException(BaseServiceException exception) {
		printException(exception);
		String message = getMessage(exception.getCode(), exception.getArgs());
		logger.error("服务错误：code={}, message={}", exception.getCode(), message);
		return new ErrorResponse(exception.getCode(), message);
	}
	
	/**
	 * 处理未知异常
	 * @param exception
	 * @return
	 */
	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
	@ExceptionHandler(value = Exception.class)
	public ErrorResponse handleDefaultException(Exception exception) {
		printException(exception);
		logger.error("系统错误：{}", exception);
		return new ErrorResponse("500", getMessage("500"));
	}
	
	private String getMessage(String code, Object... args) {
		return new RequestContext(request).getMessage(code, args);
	}

	private String buildBindExceptionMessage(BindingResult bingingResult) {
		List<FieldError> fieldErrors = bingingResult.getFieldErrors();
		if (CollectionUtils.isNotEmpty(fieldErrors)) {
			return fieldErrors.stream().map(error -> {
				return getMessage(error.getDefaultMessage());
			}).collect(Collectors.joining("\n"));
		} else {
			return getMessage("500");
		}
	}

	private void printException(Exception exception) {
//		if (Objects.nonNull(exception)) {
//			if (logger.isDebugEnabled()) {
//				exception.printStackTrace();
//			}
//		}
//		logger.error(exception.getMessage());
	}
	
}
